package br.requisiteworks.seguranca.modelo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import br.requisiteworks.modelo.Funcionario;
import br.requisiteworks.util.Entidade;
import br.requisiteworks.util.validacao.Codigo;
import br.requisiteworks.util.validacao.Nome;

@Entity
@Table(name = "tbl_usuario", uniqueConstraints = @UniqueConstraint(columnNames = { "nom_user" }))
public class Usuario extends Entidade implements UserDetails, Authentication {

	private static final long serialVersionUID = -6303146524981134730L;

	@Id
	@ManyToOne
	@JoinColumn(name = "num_funci")
	private Funcionario funcionario;

	@Codigo
	@Column(name = "cod_passw")
	private String password;

	@Nome
	@Column(name = "nom_user")
	private String username;

	@Transient
	private final boolean expired = false;

	@Transient
	private final boolean locked = false;

	@Transient
	private final boolean expiredCredentials = false;

	@Transient
	private boolean authenticated = true;

	@ManyToMany(targetEntity = Funcao.class, fetch = FetchType.EAGER)
	@JoinTable(name = "tbl_usuario_funcoes", joinColumns = @JoinColumn(name = "num_funci"))
	private Collection<GrantedAuthority> authorities;

	@Transient
	private final boolean enabled = true;

	@Override
	public Collection<GrantedAuthority> getAuthorities() {
		return authorities;
	}

	@Override
	public String getPassword() {
		return this.password;
	}

	@Override
	public String getUsername() {
		return this.username;
	}

	@Override
	public boolean isAccountNonExpired() {
		return !this.expired;
	}

	@Override
	public boolean isAccountNonLocked() {
		return !this.locked;
	}

	public boolean getLocked() {
		return this.locked;
	}

	public boolean getExpired() {
		return this.expired;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return !this.expiredCredentials;
	}

	@Override
	public boolean isEnabled() {
		return this.enabled;
	}

	@Override
	public Object getCredentials() {
		return this.password;
	}

	@Override
	public Object getDetails() {
		return this;
	}

	@Override
	public Object getPrincipal() {
		return this.funcionario;
	}

	@Override
	public boolean isAuthenticated() {
		return this.authenticated;
	}

	@Override
	public void setAuthenticated(boolean isAuthenticated)
			throws IllegalArgumentException {
		this.authenticated = isAuthenticated;

	}

	@Override
	public String getName() {
		return this.username;
	}

	public Funcionario getFuncionario() {
		return this.funcionario;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((funcionario == null) ? 0 : funcionario.hashCode());
		result = prime * result
				+ ((password == null) ? 0 : password.hashCode());
		result = prime * result
				+ ((username == null) ? 0 : username.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Usuario other = (Usuario) obj;
		if (funcionario == null) {
			if (other.funcionario != null)
				return false;
		} else if (!funcionario.equals(other.funcionario))
			return false;
		if (password == null) {
			if (other.password != null)
				return false;
		} else if (!password.equals(other.password))
			return false;
		if (username == null) {
			if (other.username != null)
				return false;
		} else if (!username.equals(other.username))
			return false;
		return true;
	}

	public void setUsername(String name) {
		this.username = name;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setFuncionario(Funcionario funcionario) {
		this.funcionario = funcionario;
	}

	public void addAuthority(GrantedAuthority authority) {
		if (this.authorities == null) {
			this.authorities = new ArrayList<GrantedAuthority>(5);
		}
		if (authority != null)
			this.authorities.add(authority);
	}

	public void setAuthorities(Collection<GrantedAuthority> authorities) {
		this.authorities = authorities;
	}

	@Override
	public String toString() {
		final int maxLen = 5;
		return String.format(
				"Usuario [username=%s, authorities=%s, funcionario=%s]",
				username, authorities != null ? toString(authorities, maxLen)
						: null, funcionario);
	}

	private String toString(Collection<?> collection, int maxLen) {
		StringBuilder builder = new StringBuilder();
		builder.append("[");
		int i = 0;
		for (Iterator<?> iterator = collection.iterator(); iterator.hasNext()
				&& i < maxLen; i++) {
			if (i > 0)
				builder.append(", ");
			builder.append(iterator.next());
		}
		builder.append("]");
		return builder.toString();
	}

}
